package com.ithero.usercenter.auth;

import com.ithero.usercenter.util.JwtOperator;
import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 认证、鉴权切面
 */
@Aspect
@Component
public class AuthAspect {

    @Autowired
    private JwtOperator jwtOperator;

    // 加了@annotation注解的方法都会走到这里
    @Around("@annotation(com.ithero.usercenter.auth.CheckLogin)")
    public Object checkLogin(ProceedingJoinPoint pjp) throws Throwable {
        try {
            checkToken();
        } catch (Throwable throwable) {
            throw new SecurityException("Token 不合法！");
        }
        return pjp.proceed();
    }

    private void checkToken() {
        // 1. 从header里获取token
        HttpServletRequest request = getHttpServletRequest();
        String token = request.getHeader("X-Token");

        // 2. 校验token 是否合法
        Boolean isValidated = jwtOperator.validateToken(token);
        if (!isValidated) {
            throw new SecurityException("Token 不合法！");
        }

        // 3. 如果校验成功，就将用户的信息设置到request的attributes里去
        Claims claims = jwtOperator.getClaimsFromToken(token);
        request.setAttribute("id", claims.get("id"));
        request.setAttribute("wxNickName", claims.get("wxNickName"));
        request.setAttribute("role", claims.get("role"));
    }

    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        return attributes.getRequest();
    }

    @Around("@annotation(com.ithero.usercenter.auth.CheckAuthorization)")
    public Object checkAuthorization(ProceedingJoinPoint pjp) throws Throwable {
        try {
            // 1. 校验token 是否合法
            this.checkToken();
            // 2. 验证用户角色是否匹配
            HttpServletRequest request = this.getHttpServletRequest();
            String role = (String) request.getAttribute("role");

            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Method method = signature.getMethod();
            CheckAuthorization annotation = method.getAnnotation(CheckAuthorization.class);

            // 拿到注解上标注的所需角色
            String value = annotation.value();

            if (!Objects.equals(role, value)) {
                throw new SecurityException("用户无权访问！");
            }
        } catch (Throwable throwable) {
            throw new SecurityException("用户无权访问！", throwable);
        }
        return pjp.proceed();
    }
}
